import org.apache.poi.xwpf.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Excel2 {

    public static void main(String[] args) throws IOException {
        String inputPath = "./test.docx";
        String outputPath = "output.docx";

        Map<String, String> data = new HashMap<>();
        data.put("@name@", "李四");
        data.put("@position@", "产品经理");
        data.put("@department@", "产品部");
        data.put("@date@", "2023-11-01");

        try (FileInputStream fis = new FileInputStream(inputPath);
             XWPFDocument document = new XWPFDocument(fis)) {

            // 替换段落中的占位符
            replaceInParagraphs(document.getParagraphs(), data);

            // 替换表格中的占位符
            for (XWPFTable table : document.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        replaceInParagraphs(cell.getParagraphs(), data);
                    }
                }
            }

            try (FileOutputStream fos = new FileOutputStream(outputPath)) {
                document.write(fos);
            }
            System.out.println("健壮替换完成！");
        }
    }

    /**
     * 替换段落列表中的占位符
     */
    public static void replaceInParagraphs(List<XWPFParagraph> paragraphs, Map<String, String> data) {
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            if (runs == null || runs.isEmpty()) {
                continue;
            }

            // 【改进点】使用 toString() 来拼接，以应对复杂的Run
            StringBuilder fullTextBuilder = new StringBuilder();
            for (XWPFRun run : runs) {
                // run.toString() 可以获取一个Run内部的所有文本内容，包括被tab等分隔的
                fullTextBuilder.append(run.toString());
            }
            String fullText = fullTextBuilder.toString();

            boolean found = false;
            for (String key : data.keySet()) {
                if (fullText.contains(key)) {
                    found = true;
                    break;
                }
            }

            if (found) {
                // 替换所有占位符
                for (Map.Entry<String, String> entry : data.entrySet()) {
                    fullText = fullText.replace(entry.getKey(), entry.getValue());
                }

                // 清除所有旧的Run
                for (int i = runs.size() - 1; i >= 0; i--) {
                    paragraph.removeRun(i);
                }

                // 创建一个包含所有替换后内容的新Run
                XWPFRun newRun = paragraph.createRun();
                newRun.setText(fullText);

                // 复制原始第一个run的样式
                if (!runs.isEmpty()) {
                    newRun.getCTR().setRPr(runs.get(0).getCTR().getRPr());
                }
            }
        }
    }
}